package org.dashboard.server.messageflow;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import org.dashboard.client.widget.messageflow.MessageFlowService;
import org.dashboard.shared.Props;

import java.sql.*;
import java.util.*;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class MessageFlowServiceImpl extends RemoteServiceServlet implements MessageFlowService {

    static {
        try {
//            Class.forName("org.hsqldb.jdbcDriver").newInstance();
            Class.forName("com.ibm.db2.jcc.DB2Driver").newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }


    private List<Integer> newGraphValues;
    private List<Integer> inqueueGraphValues;
    private List<Integer> processingGraphValues;
    private final String[][] newAndProcessing = new String[4][4];


    public MessageFlowServiceImpl() {
        newGraphValues = new ArrayList<Integer>(23);
        processingGraphValues = new ArrayList<Integer>(23);
        inqueueGraphValues = new ArrayList<Integer>(23);

        for (int i = 0; i != 23; i++) {
            newGraphValues.add(0);
            processingGraphValues.add(0);
            inqueueGraphValues.add(0);
        }


        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                maintainNewAndProcessing();
            }
        };
        Timer timer = new Timer("update new and processing timer");
        timer.schedule(timerTask, 0, 5 * 60 * 1000);


    }

    public String getDailyProcessingFlowUrl() throws IllegalArgumentException {
        return getProcessingLast24Hours();
    }


    public String getDailyMessageFlowUrl() throws IllegalArgumentException {
        //return getToday();
        return getNewLast24Hours();
    }

    public String getNewAndProcessingGraph() throws IllegalArgumentException {
        String url = "http://chart.apis.google.com/chart" +
                "?chxl=1:|-120|-110|-105|-100|-95|-90|-85|-80|-75|-70|-65|-60|-50|-45|-40|-35|-30|-25|-20|-15|-10|-5|0" +
                "&chxr=0,0,--MAX--|1,0,23" +
                "&chxs=0,676767,11.5,0,lt,676767" +
                "&chxt=y,x" +
                "&chs=580x280" +
                "&cht=lc" +
                "&chco=FF0000,00FF00,FF9900" +
                "&chds=0,--MAX--,0,--MAX--,0,--MAX--" +
                "&chd=t:--NEW--|--PROCESSING--|--INQUEUE--" +
                "&chdl=New|Processing|Inqueue" +
                "&chdlp=b" +
                "&chg=10,-1,1,1" +
                "&chls=5|5|5" +
                "&chtt=New+,+Inqueue+and+Processing+flow+last+2+hours";

        //Find max value
        int max = 0;
        for (int value : newGraphValues) {
            max = Math.max(max, value);
        }
        for (int value : processingGraphValues) {
            max = Math.max(max, value);
        }
        for (int value : inqueueGraphValues) {
            max = Math.max(max, value);
        }

        url = url.replaceAll("--MAX--", max + "");
        url = url.replaceAll("--NEW--", getNewGraphData());
        url = url.replaceAll("--PROCESSING--", getProcessingGraphData());
        url = url.replaceAll("--INQUEUE--", getInQueueGraphData());

        System.out.println(url);

        return url;
    }

    private String getInQueueGraphData() {
        StringBuilder sb = new StringBuilder();
        for (Integer s : inqueueGraphValues) {
            sb.append(s + ",");
        }
        return sb.deleteCharAt(sb.lastIndexOf(",")).toString();
    }

    private String getProcessingGraphData() {
        StringBuilder sb = new StringBuilder();
        for (Integer s : processingGraphValues) {
            sb.append(s + ",");
        }
        return sb.deleteCharAt(sb.lastIndexOf(",")).toString();
    }

    private String getNewGraphData() {
        StringBuilder sb = new StringBuilder();
        for (Integer s : newGraphValues) {
            sb.append(s + ",");
        }
        return sb.deleteCharAt(sb.lastIndexOf(",")).toString();
    }

    private void addInqueueGraphValue(String value) {
        for (int i = 0; i != inqueueGraphValues.size() - 1; i++) {
            inqueueGraphValues.set(i, inqueueGraphValues.get(i + 1));
        }
        inqueueGraphValues.set(inqueueGraphValues.size() - 1, Integer.parseInt(value));

    }


    private void addNewGraphValue(String value) {
        for (int i = 0; i != newGraphValues.size() - 1; i++) {
            newGraphValues.set(i, newGraphValues.get(i + 1));
        }
        newGraphValues.set(newGraphValues.size() - 1, Integer.parseInt(value));

    }

    private void addProcessingGraphValue(String value) {
        for (int i = 0; i != processingGraphValues.size() - 1; i++) {
            processingGraphValues.set(i, processingGraphValues.get(i + 1));
        }
        processingGraphValues.set(processingGraphValues.size() - 1, Integer.parseInt(value));

    }

    public String[][] getNewAndProcessing() throws IllegalArgumentException {
        return newAndProcessing;
    }


    private void maintainNewAndProcessing() throws IllegalArgumentException {
        newAndProcessing[0][0] = "0";
        newAndProcessing[0][1] = "NEW";
        newAndProcessing[0][2] = "-";
        newAndProcessing[0][3] = "Time asked";
        newAndProcessing[1][0] = "0";
        newAndProcessing[1][1] = "INQUEUE";
        newAndProcessing[1][2] = "-";
        newAndProcessing[1][3] = "Time asked";
        newAndProcessing[2][0] = "0";
        newAndProcessing[2][1] = "PROCESSING";
        newAndProcessing[2][2] = "-";
        newAndProcessing[2][3] = "Time asked";
        newAndProcessing[3][0] = "0";
        newAndProcessing[3][1] = "SUSPENDED";
        newAndProcessing[3][2] = "-";
        newAndProcessing[3][3] = "Time asked";

        Connection con = null;
        try {
            Props props = Props.instance();
            String[] messageCountConfig = props.getMessagesInStateNew();
            String sql = messageCountConfig[0];
            String url = messageCountConfig[1];
            String user = messageCountConfig[2];
            String pass = messageCountConfig[3];

            con = DriverManager.getConnection(url, user, pass);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();

            while (rs.next()) {
                newAndProcessing[0][0] = rs.getString(1); //antal
                newAndProcessing[0][1] = rs.getString(2); //state
                newAndProcessing[0][2] = rs.getString(3); //avg
                newAndProcessing[0][3] = rs.getString(4); //time asked

            }

            messageCountConfig = props.getMessagesInStateInqueue();
            sql = messageCountConfig[0];

            ps = con.prepareStatement(sql);
            rs = ps.executeQuery();
            while (rs.next()) {
                newAndProcessing[1][0] = rs.getString(1); //antal
                newAndProcessing[1][1] = rs.getString(2); //state
                newAndProcessing[1][2] = rs.getString(3); //avg
                newAndProcessing[1][3] = rs.getString(4); //time asked

            }

            messageCountConfig = props.getMessagesInStateProcessing();
            sql = messageCountConfig[0];

            ps = con.prepareStatement(sql);
            rs = ps.executeQuery();
            while (rs.next()) {
                newAndProcessing[2][0] = rs.getString(1); //antal
                newAndProcessing[2][1] = rs.getString(2); //state
                newAndProcessing[2][2] = rs.getString(3); //avg
                newAndProcessing[2][3] = rs.getString(4); //time asked

            }

            messageCountConfig = props.getMessagesInStateSuspended();
            sql = messageCountConfig[0];

            ps = con.prepareStatement(sql);
            rs = ps.executeQuery();
            while (rs.next()) {
                newAndProcessing[3][0] = rs.getString(1); //antal
                newAndProcessing[3][1] = rs.getString(2); //state
                newAndProcessing[3][2] = rs.getString(3); //avg
                newAndProcessing[3][3] = rs.getString(4); //time asked

            }


            ps.close();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        //update
        addNewGraphValue(newAndProcessing[0][0]);
        addInqueueGraphValue(newAndProcessing[1][0]);
        addProcessingGraphValue(newAndProcessing[2][0]);
    }

    public String[][] getTodayMessagesHandledOrFailed() throws IllegalArgumentException {
        String[][] result = new String[3][4];

        for (int i = 0; i != 3; i++) {
            for (int y = 0; y != 4; y++) {
                result[i][y] = "-";
            }
        }

        Connection con = null;
        try {
            Props props = Props.instance();
            String[] messageCountConfig = props.getTodayMessagesHandledOrFailed();
            String sql = messageCountConfig[0];
            String url = messageCountConfig[1];
            String user = messageCountConfig[2];
            String pass = messageCountConfig[3];

            con = DriverManager.getConnection(url, user, pass);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            int i = 0;
            while (rs.next()) {
                result[i][0] = rs.getString(1); //antal
                result[i][1] = rs.getString(2); //state
                result[i][2] = rs.getString(3); //avg
                result[i][3] = rs.getString(4); //time of day
                i++;
            }
            ps.close();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    public String[][] getYesterdayMessagesHandledOrFailed() throws IllegalArgumentException {
        String[][] result = new String[3][4];

        for (int i = 0; i != 3; i++) {
            for (int y = 0; y != 4; y++) {
                result[i][y] = "-";
            }
        }

        Connection con = null;
        try {
            Props props = Props.instance();
            String[] messageCountConfig = props.getYesterdayMessagesHandledOrFailed();
            String sql = messageCountConfig[0];
            String url = messageCountConfig[1];
            String user = messageCountConfig[2];
            String pass = messageCountConfig[3];

            con = DriverManager.getConnection(url, user, pass);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            int i = 0;
            while (rs.next()) {
                result[i][0] = rs.getString(1); //antal
                result[i][1] = rs.getString(2); //state
                result[i][2] = rs.getString(3); //avg
                result[i][3] = rs.getString(4); //time of day
                i++;
            }
            ps.close();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    public String[][] getTotalMessagesHandledOrFailed() throws IllegalArgumentException {
        String[][] result = new String[3][4];

        for (int i = 0; i != 3; i++) {
            for (int y = 0; y != 4; y++) {
                result[i][y] = "-";
            }
        }

        Connection con = null;
        try {
            Props props = Props.instance();
            String[] messageCountConfig = props.getTotalMessagesHandledOrFailed();
            String sql = messageCountConfig[0];
            String url = messageCountConfig[1];
            String user = messageCountConfig[2];
            String pass = messageCountConfig[3];

            con = DriverManager.getConnection(url, user, pass);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            int i = 0;
            while (rs.next()) {
                result[i][0] = rs.getString(1); //antal
                result[i][1] = rs.getString(2); //state
                result[i][2] = rs.getString(3); //avg
                result[i][3] = rs.getString(4); //time of day
                i++;
            }
            ps.close();

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return result;
    }

    private String getProcessingLast24Hours() {
        String imageUrl = "http://chart.apis.google.com/chart" +
                "?chxl=1:--X-LABELS--" +
                "&chxr=0,0,--MAX--|1,0,23" +
                "&chxs=0,676767,11.5,0,lt,676767" +
                "&chxt=y,x" +
                "&chs=580x280" +
                "&cht=lc" +
                "&chco=3D7930" +
                "&chds=0,--MAX--" +
                "&chd=t:--REPLACEME--" +
                "&chg=10,-1,1,1" +
                "&chls=2,4,0" +
                "&chm=B,C5D4B5BB,0,0,0" +
                "&chtt=Average+processing+time+in+seconds";

        String data[] = new String[24];
        for (int i = 0; i != data.length; i++) {
            data[i] = "0";
        }

        Connection con = null;
        try {
            Props props = Props.instance();
            String[] messageCountConfig = props.get24HoursProcessingFlowConfig();
            String sql = messageCountConfig[0];
            String url = messageCountConfig[1];
            String user = messageCountConfig[2];
            String pass = messageCountConfig[3];

            con = DriverManager.getConnection(url, user, pass);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            int max = 0;
            while (rs.next()) {
                String count = rs.getString(1);
                String hour = rs.getString(2);
                int i = Integer.parseInt(count);
                max = Math.max(i, max);
                data[Integer.parseInt(hour)] = count;
            }
            ps.close();

            Calendar cal = Calendar.getInstance();
            String[] sortedData = sortAfterCurrentTime(data, cal);
            String dataString = convertDataToString(sortedData);
            String xaxis = getXaxisValvesAfterCurrentTime(cal);


            imageUrl = imageUrl.replaceAll("--REPLACEME--", dataString);
            imageUrl = imageUrl.replaceAll("--MAX--", max + "");
            imageUrl = imageUrl.replaceAll("--X-LABELS--", xaxis);

            System.out.println(imageUrl);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return imageUrl;
    }

    private synchronized String getXaxisValvesAfterCurrentTime(Calendar calendar) {
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        StringBuilder xsb = new StringBuilder();
        for (int i = hour + 1; i != 24; i++) {
            xsb.append("|" + i);
        }
        for (int i = 0; i <= hour; i++) {
            xsb.append("|" + i);
        }

        return xsb.toString();
    }

    private synchronized String convertDataToString(String[] sortedData) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i != sortedData.length; i++) {
            sb.append(sortedData[i]);
            if ((i + 1) != sortedData.length) {
                sb.append(",");
            }
        }

        return sb.toString();
    }

    private synchronized String[] sortAfterCurrentTime(String[] data, Calendar calendar) {
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        String[] sortedData = new String[24];
        int taeller = 0;
        for (int i = hour + 1; i != 24; i++) {
            sortedData[taeller] = data[i];
            taeller++;
        }
        for (int i = 0; i <= hour; i++) {
            sortedData[taeller] = data[i];
            taeller++;
        }

        return sortedData;
    }

    private String getNewLast24Hours() {
        String imageUrl = "http://chart.apis.google.com/chart" +
                "?chxl=1:--X-LABELS--" +
                "&chxr=0,0,--MAX--|1,0,23" +
                "&chxs=0,676767,11.5,0,lt,676767" +
                "&chxt=y,x" +
                "&chs=580x280" +
                "&cht=lc" +
                "&chco=76A4FB" +
                "&chds=0,--MAX--" +
                "&chd=t:--REPLACEME--" +
                "&chg=10,-1,1,1" +
                "&chls=2,4,0" +
                "&chm=B,FFCC33,0,0,0" +
                "&chtt=incoming+eTL+message+flow";

        String data[] = new String[24];
        for (int i = 0; i != data.length; i++) {
            data[i] = "0";
        }

        Connection con = null;
        try {
            Props props = Props.instance();
            String[] messageCountConfig = props.get24HoursMessageFlowConfig();
            String sql = messageCountConfig[0];
            String url = messageCountConfig[1];
            String user = messageCountConfig[2];
            String pass = messageCountConfig[3];

            con = DriverManager.getConnection(url, user, pass);
            PreparedStatement ps = con.prepareStatement(sql);
            ResultSet rs = ps.executeQuery();
            int max = 0;
            while (rs.next()) {
                String count = rs.getString(1);
                String hour = rs.getString(2);
                int i = Integer.parseInt(count);
                max = Math.max(i, max);
                data[Integer.parseInt(hour)] = count;
            }
            ps.close();

            Calendar cal = Calendar.getInstance();
            String[] sortedData = sortAfterCurrentTime(data, cal);
            String dataString = convertDataToString(sortedData);
            String xaxis = getXaxisValvesAfterCurrentTime(cal);

            imageUrl = imageUrl.replaceAll("--REPLACEME--", dataString);
            imageUrl = imageUrl.replaceAll("--MAX--", max + "");
            imageUrl = imageUrl.replaceAll("--X-LABELS--", xaxis);

            System.out.println(imageUrl);

        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            try {
                if (con != null) con.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

        return imageUrl;
    }
}
